#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include "platform_data_special.h"
#include "stm32mp157xxx.h"

#define SHOW_DATA _IOR('S',0X01,unsigned short)
char seg_code[]={
	0x3f,/*display 0*/	
    0x06,/*display 1*/	
    0x5b,/*display 2*/	
    0x4f,/*display 3*/	
    0x66,/*display 4*/	
    0x6d,/*display 5*/	
    0x7d,/*display 6*/	
    0x07,/*display 7*/	
    0x7f,/*display 8*/	
    0x6f, /*display 9*/
    0x77,/*A*/
    0x7c,/*b*/
    0x39,/*C*/
    0x5e,/*d*/
    0x79,/*E*/
    0x71/*F*/
};

struct stm32mp157a{
	unsigned int major;
	struct resource *resource[5];
	struct class *cls;
	struct device *dev;
	unsigned int gpio_count;
	struct gpio_desc **get_gpios;
	struct Platform_data_spex *spex;
	struct spi_device *spi;
};
struct stm32mp157a *drv_spi;
int drv_spi_open(struct inode *ide, struct file *filp)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	
	return ret;
}
	
int drv_spi_close(struct inode *ide, struct file *filp)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	return ret;
}
ssize_t drv_spi_write(struct file *flp, const char __user *buf, size_t size , loff_t *flag)
{
	int ret =0;
	int spi_status=0;
	int i;
	printk("---%s---\r\n",__FUNCTION__);
	ret = copy_from_user(&spi_status, buf, size);
	if(ret !=0)
	{
		printk("copy_from_user_err\r\n");
		return ret;
	}
	if(spi_status == 0)	
	{
		for(i=0;i<drv_spi->gpio_count;i++)
		{	
			gpiod_set_value(drv_spi->get_gpios[i],0);
		}
	}
	else
	{
		for(i=0;i<drv_spi->gpio_count;i++)
		{	
			gpiod_set_value(drv_spi->get_gpios[i],1);
		}
	}
	return ret;
}
void spi_show_data(char idex, char data)
{
	struct spi_message message;
	struct spi_transfer xfer[2];
	char tx_buf[2];
	spi_message_init(&message);
	memset(xfer, 0, sizeof(xfer));
	tx_buf[0] = idex;
	tx_buf[1] = data;
	xfer[0].tx_buf = tx_buf;
	xfer[0].len = ARRAY_SIZE(tx_buf);
	spi_message_add_tail(&xfer[0], &message);
	spi_sync(drv_spi->spi, &message);
}
long drv_spi_ioctl(struct file *flp, unsigned int cmd, unsigned long data)
{
	long ret =0;
	char idex,code;
	printk("---%s---\r\n",__FUNCTION__);
	switch(cmd)
	{
		case SHOW_DATA:
				idex=data&0xff;
				code = seg_code[(data>>8)&0xff];
				spi_show_data(idex, code);
			break;
		default:
				printk("NOT CMD\r\n");
			break;

	}
	
	return ret;
}

const struct file_operations fops={
	.open = drv_spi_open,
	.release = drv_spi_close,
	.write = drv_spi_write,
	.unlocked_ioctl = drv_spi_ioctl,
};

int drv_spi_probe(struct spi_device *spi)
{
	int ret =0;
	//int i=0;
	//char name_string[10];
	printk("---%s---\r\n",__FUNCTION__);


	//实例化一个对象
	drv_spi= kzalloc(sizeof(struct stm32mp157a), GFP_KERNEL);
	if(IS_ERR(drv_spi))
	{
		printk("kzalloc_err\r\n");
		ret = PTR_ERR(drv_spi);
		return ret;
	}
	drv_spi->spex = kzalloc(sizeof(struct Platform_data_spex), GFP_KERNEL);
	if(IS_ERR(drv_spi->spex))
	{
		printk("spex_kzalloc_err\r\n");
		ret = PTR_ERR(drv_spi->spex);
		goto spex_kzalloc_err;
	}
	of_property_read_u32_index(spi->dev.of_node, "minum", 0, &drv_spi->spex->minum);
	of_property_read_string(spi->dev.of_node, "spi_name", &drv_spi->spex->name);
	printk("minum=%d name=%s\r\n",drv_spi->spex->minum,drv_spi->spex->name);


	//申请设备号
	drv_spi->major = register_chrdev(0, drv_spi->spex->name, &fops);
	if(drv_spi->major < 0)
	{
		printk("register_chrdev_err\r\n");
		goto register_chrdev_err;
	}
	printk("major=%d \r\n",drv_spi->major);
	//创建类
	drv_spi->cls = class_create(THIS_MODULE, drv_spi->spex->name);
	if(IS_ERR(drv_spi->cls))
	{
		printk("class_create_err\r\n");
		ret = PTR_ERR(drv_spi->cls);
		goto class_create_err;
	}
	//创建节点
	drv_spi->dev = device_create(drv_spi->cls, NULL, MKDEV(drv_spi->major, drv_spi->spex->minum), NULL, drv_spi->spex->name);
	if(IS_ERR(drv_spi->dev))
	{
		printk("device_create_err\r\n");
		ret = PTR_ERR(drv_spi->dev);
		goto device_create_err;
	}
	drv_spi->spi = spi;
	return ret;
#if 0


	//硬件初始化
	//获取GPIO数量
	drv_spi->gpio_count = gpiod_count(&pdev->dev,"spi");
	if(drv_spi->gpio_count < 0)
	{
		printk("of_gpio_count_err\r\n");
		ret = drv_spi->gpio_count;
		goto of_gpio_count_err;
	}
	printk("gpio_count=%d\r\n",drv_spi->gpio_count);
	//获取gpio标号
	drv_spi->get_gpios = kzalloc(sizeof(struct gpio_desc *)*drv_spi->gpio_count,GFP_KERNEL);
	if(IS_ERR(drv_spi->get_gpios))
	{
		printk("get_gpios_kzalloc_err\r\n");
		ret = PTR_ERR(drv_spi->get_gpios);
		goto get_gpios_kzalloc_err;
	}
	for(i=0;i<drv_spi->gpio_count;i++)
	{
		//drv_spi->get_gpios[i] = gpiod_get_index(&pdev->dev, "spi",i, GPIOD_OUT_LOW);
		drv_spi->get_gpios[i] = devm_gpiod_get_index(&pdev->dev, "spi",i, GPIOD_OUT_LOW);//带资源管理的接口函数，用此函数获取标号不需要手动释放使用权
		gpiod_direction_output(drv_spi->get_gpios[i],0);
	}
	return ret;	
get_gpios_kzalloc_err:

of_gpio_count_err:
	device_destroy(drv_spi->cls, MKDEV(drv_spi->major, drv_spi->spex->minum));
#endif

device_create_err:
	class_destroy(drv_spi->cls );
class_create_err:
	unregister_chrdev(drv_spi->major,drv_spi->spex->name);
register_chrdev_err:
	kfree(drv_spi->spex);
spex_kzalloc_err:
	kfree(drv_spi);


	return ret;
}
int drv_spi_remove(struct spi_device *spi)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	
#if 0
	kfree(drv_spi->get_gpios);

#endif

	device_destroy(drv_spi->cls, MKDEV(drv_spi->major, drv_spi->spex->minum));
	class_destroy(drv_spi->cls );
	unregister_chrdev(drv_spi->major,drv_spi->spex->name);
	
	kfree(drv_spi->spex);
	kfree(drv_spi);


	return ret;
}


const struct of_device_id spi_table[]={
	{ .compatible = "spi_m74hc595" },
};
	
struct spi_driver drv={
	.probe = drv_spi_probe,
	.remove = drv_spi_remove,
	.driver = {
		.name = "74hc595",
		.of_match_table = spi_table,
	}, 
};

static int __init drv_spi_init(void)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	spi_register_driver(&drv);
	return ret;
}
void __exit drv_spi_exit(void)
{
	printk("---%s---\r\n",__FUNCTION__);
	spi_unregister_driver(&drv);
}

module_init(drv_spi_init);
module_exit(drv_spi_exit);
MODULE_LICENSE("GPL");

